#include <stdio.h>

#include <stdlib.h>

/* #include <error.h> */

#include <string.h>

#include <sys/socket.h>

#include <sys/types.h>

#include <netinet/in.h>

#include <arpa/inet.h>

#include <time.h>



static void printmessage(unsigned char *buf);

static unsigned char *printnamestring(unsigned char *p,unsigned char *buf);



#define GETWORD(__w,__p) do{__w=*(__p++)<<8;__w|=*(p++);}while(0)

#define GETLONG(__l,__p) do{__l=*(__p++)<<24;__l|=*(__p++)<<16;__l|=*(__p++)<<8;__l|=*(p++);}while(0)



int main(int argc,char* argv[])

{

    if(argc != 2)

    {

       printf("usage: dnsclient <host_name>\n");

       return -1;

    }



    time_t ident;

    int fd;

    int rc;

    int serveraddrlent;

    char *q;

    unsigned char *p;

    unsigned char *countp;

    unsigned char reqBuf[512] = {0};

    unsigned char rplBuf[512] = {0};

    struct sockaddr_in serveraddr;



    //udp

    fd = socket(AF_INET, SOCK_DGRAM, 0);

    if(fd == -1)

    {

       perror("error create udp socket");

       return -1;

    }



    time(&ident);

    //copy

    p = reqBuf;

    //Transaction ID

    *(p++) = ident;

    *(p++) = ident>>8;

    //Header section

    //flag word = 0x0100

    *(p++) = 0x01;

    *(p++) = 0x00;

    //Questions = 0x0001

    //just one query

    *(p++) = 0x00;

    *(p++) = 0x01;

    //Answer RRs = 0x0000

    //no answers in this message

    *(p++) = 0x00;

    *(p++) = 0x00;

    //Authority RRs = 0x0000

    *(p++) = 0x00;

    *(p++) = 0x00;

    //Additional RRs = 0x0000

    *(p++) = 0x00;

    *(p++) = 0x00;

    //Query section

    countp = p;

    *(p++) = 0;

    for(q=argv[1]; *q!=0; q++)

    {

       if(*q != '.')

       {

           (*countp)++;

           *(p++) = *q;

       }

       else if(*countp != 0)

       {

           countp = p;

           *(p++) = 0;

       }

    }

    if(*countp != 0)

       *(p++) = 0;



    //Type=1(A):host address

    *(p++)=0;

    *(p++)=1;

    //Class=1(IN):internet

    *(p++)=0;

    *(p++)=1;



    printf("\nRequest:\n");

    printmessage(reqBuf);



    //fill

    bzero(&serveraddr, sizeof(serveraddr));

    serveraddr.sin_family = AF_INET;

    serveraddr.sin_port = htons(53);

    serveraddr.sin_addr.s_addr = inet_addr("192.168.1.1");



    //send to DNS Serv

    if(sendto(fd,reqBuf,p-reqBuf,0,(void *)&serveraddr,sizeof(serveraddr)) < 0)

    {

       perror("error sending request");

       return -1;

    }



    //recev the reply

    bzero(&serveraddr,sizeof(serveraddr));

    serveraddrlent = sizeof(serveraddr);

    rc = recvfrom(fd,&rplBuf,sizeof(rplBuf),0,(void *)&serveraddr,&serveraddrlent);

    if(rc < 0)

    {

       perror("error receiving request\n");

       return -1;

    }



    //print out results

    printf("\nReply:\n");

    printmessage(rplBuf);



    //exit

    printf("Program Exit\n");

    return 0;

}



static void printmessage(unsigned char *buf)

{

    unsigned char *p;

    unsigned int ident,flags,qdcount,ancount,nscount,arcount;

    unsigned int i,j,type,class,ttl,rdlength;



    p = buf;

    GETWORD(ident,p);

    printf("ident=%#x\n",ident);



    GETWORD(flags,p);

    printf("flags=%#x\n",flags);

    //printf("qr=%u\n",(flags>>15)&1);

    printf("qr=%u\n",flags>>15);



    printf("opcode=%u\n",(flags>>11)&15);

    printf("aa=%u\n",(flags>>10)&1);

    printf("tc=%u\n",(flags>>9)&1);

    printf("rd=%u\n",(flags>>8)&1);

    printf("ra=%u\n",(flags>>7)&1);

    printf("z=%u\n",(flags>>4)&7);

    printf("rcode=%u\n",flags&15);



    GETWORD(qdcount,p);

    printf("qdcount=%u\n",qdcount);



    GETWORD(ancount,p);

    printf("ancount=%u\n",ancount);



    GETWORD(nscount,p);

    printf("nscount=%u\n",nscount);



    GETWORD(arcount,p);

    printf("arcount=%u\n",arcount);



    for(i=0; i<qdcount; i++)

    {

       printf("qd[%u]:\n",i);

       while(*p!=0)

       {

           p = printnamestring(p,buf);

           if(*p != 0)

              printf(".");

       }

       p++;

       printf("\n");

       GETWORD(type,p);

       printf("type=%u\n",type);

       GETWORD(class,p);

       printf("class=%u\n",class);

    }



    for(i=0; i<ancount; i++)

    {

       printf("an[%u]:\n",i);

       p = printnamestring(p,buf);

       printf("\n");

       GETWORD(type,p);

       printf("type=%u\n",type);

       GETWORD(class,p);

       printf("class=%u\n",class);

       GETLONG(ttl,p);

       printf("ttl=%u\n",ttl);

       GETWORD(rdlength,p);

       printf("rdlength=%u\n",rdlength);

       printf("rd=");

       for(j=0; j<rdlength; j++)

       {

           printf("%2.2x(%u)",*p,*p);

           p++;

       }

       printf("\n");

    }

}



static unsigned char *printnamestring(unsigned char *p,unsigned char *buf)

{

    unsigned int nchars,offset;



    nchars = *(p++);

    if((nchars & 0xc0) == 0xc0)

    {

       offset = (nchars & 0x3f) << 8;

       offset |= *(p++);

       nchars = buf[offset++];

       printf("%*.*s",nchars,nchars,buf+offset);

    }

    else

    {

       printf("%*.*s",nchars,nchars,p);

       p += nchars;

    }



    return (p);

}


